package com.jwds.digital.bios.business.service.service.belt.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwds.digital.bios.business.core.exceptions.RecordNotFoundException;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.BeltRoutePerformanceHourReqDTO;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.assembler.BeltRoutePerformanceHourAssembler;
import com.jwds.digital.bios.business.core.infrastructure.entity.basic.BasicDevice;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltDayTargetHis;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltPerformanceHour;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltPerformanceMinute;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltRoutePerformanceHour;
import com.jwds.digital.bios.business.core.infrastructure.entity.flow.FlowBasic;
import com.jwds.digital.bios.business.core.infrastructure.mapper.basic.BasicDeviceMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceHourMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceMinuteMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRoutePerformanceHourMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.flow.FlowBasicMapper;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.*;
//import com.jwds.digital.bios.business.core.infrastructure.vo.flow.FlowBasicRespVO;
import com.jwds.digital.bios.business.core.infrastructure.vo.feign.FlowBasicRespVO;
import com.jwds.digital.bios.business.rpc.feign.FlowBasicFeign;
import com.jwds.digital.bios.business.service.service.belt.IBeltDayTargetHisService;
import com.jwds.digital.bios.business.service.service.belt.IBeltRoutePerformanceHourService;
import com.jwds.tdc.framework.application.lib.page.PageRequest;
import com.jwds.tdc.framework.application.lib.page.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 线路效能小时表实现类
 *
 * @author 林柏云
 * @date 2024-10-24
 */
@Slf4j
@Service
public class BeltRoutePerformanceHourServiceImpl extends ServiceImpl<BeltRoutePerformanceHourMapper, BeltRoutePerformanceHour> implements IBeltRoutePerformanceHourService {

    @Autowired
    private BeltRoutePerformanceHourMapper baseMapper;
    @Autowired
    private IBeltDayTargetHisService beltDayTargetHisService;

    @Override
    public BeltRoutePerformanceHourRespVO queryById(Long id) {
        if (id == null) {
            return null;
        }
        BeltRoutePerformanceHour entity = baseMapper.selectById(id);
        return BeltRoutePerformanceHourAssembler.entity2dto(entity);
    }

    @Override
    public PageResponse<BeltRoutePerformanceHourRespVO> page(PageRequest<BeltRoutePerformanceHourReqDTO> request) {
        BeltRoutePerformanceHourReqDTO condition = request.getQueryCondition();
        Page<BeltRoutePerformanceHourRespVO> page = new Page<>(request.getPageIndex(), request.getPageSize());
        IPage<BeltRoutePerformanceHourRespVO> pageData = baseMapper.pageQuery(page, condition);
        return new PageResponse<>((Page<?>) pageData, pageData.getRecords());
    }

    @Override
    public List<BeltRoutePerformanceHourRespVO> list(BeltRoutePerformanceHourReqDTO reqDto) {
        return baseMapper.queryList(reqDto);
    }

    @Override
    public void add(BeltRoutePerformanceHourReqDTO reqDto) {
        BeltRoutePerformanceHour entity = BeltRoutePerformanceHourAssembler.dto2entity(reqDto);
        baseMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAdd(List<BeltRoutePerformanceHourReqDTO> dtoList) {
        dtoList.forEach(this::add);
    }

    @Override
    public void update(BeltRoutePerformanceHourReqDTO reqDto) {
        BeltRoutePerformanceHour oldEntity = baseMapper.selectById(reqDto.getId());
        if (oldEntity == null) {
            throw new RecordNotFoundException();
        }
        BeltRoutePerformanceHour newEntity = BeltRoutePerformanceHourAssembler.dto2entity(reqDto, oldEntity);
        baseMapper.updateById(newEntity);
    }

    @Override
    public void delete(Long id) {
        BeltRoutePerformanceHour oldEntity = baseMapper.selectById(id);
        if (oldEntity == null) {
            throw new RecordNotFoundException();
        }
        baseMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Long> ids) {
        for (Long id : ids) {
            delete(id);
        }
    }
    @Autowired
    private BeltPerformanceMinuteMapper beltPerformanceMinuteMapper;
    @Override
    public BeltRoutePerformanceHourRespVO getLineEfficiencyHour(Long routeId) {


        // 线路效能小时基本信息
        BeltRoutePerformanceHourRespVO lineEfficiencyHour = baseMapper.getLineEfficiencyHour(routeId);

        if (lineEfficiencyHour == null) {
            return null;
        }

        // 启动空转时间
        BigDecimal between = new BigDecimal(ChronoUnit.HOURS.between(lineEfficiencyHour.getStartTime(), lineEfficiencyHour.getEndTime()));
        lineEfficiencyHour.setStartIdleTimeInOperation(between);
        // 停止空转时间
        BigDecimal emptyTime = new BigDecimal(ChronoUnit.HOURS.between(lineEfficiencyHour.getStartEmptyTime(), lineEfficiencyHour.getEndEmptyTime()));
        lineEfficiencyHour.setEndIdleTimeInOperation(emptyTime);
        // 运行中空载时间
        lineEfficiencyHour.setIdleTimeInOperation(lineEfficiencyHour.getNoLoadRuntime().subtract(between).subtract(emptyTime));
        // 启动空转时间占比
        lineEfficiencyHour.setStartIdleTimeConsumptionRatio(between.divide(lineEfficiencyHour.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
        // 停止空转时间占比
        lineEfficiencyHour.setEndIdleTimeConsumptionRatio(emptyTime.divide(lineEfficiencyHour.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
        // 运行中空载时间占比
        lineEfficiencyHour.setInOperationIdleTImeConsumptionRatio(lineEfficiencyHour.getIdleTimeInOperation().divide(lineEfficiencyHour.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));
        // 运行中空载能耗
        lineEfficiencyHour.setIdleEnergyInOperation(lineEfficiencyHour.getNoLoadPowerConsumption().subtract(lineEfficiencyHour.getStartNoLoadPowerConsumption()).subtract(lineEfficiencyHour.getEndNoLoadPowerConsumption()));
        // 运行中空载能耗占比
        lineEfficiencyHour.setInOperationIdleEnergyConsumptionRatio(lineEfficiencyHour.getIdleEnergyInOperation().divide(lineEfficiencyHour.getNoLoadPowerConsumption()));
        // 启动空载能耗占比
        lineEfficiencyHour.setStartIdleTimeConsumptionRatio(lineEfficiencyHour.getStartNoLoadPowerConsumption().divide(lineEfficiencyHour.getNoLoadPowerConsumption()));
        // 停止空载能耗占比
        lineEfficiencyHour.setStartIdleTimeConsumptionRatio(lineEfficiencyHour.getEndNoLoadPowerConsumption().divide(lineEfficiencyHour.getNoLoadPowerConsumption()));

        // 计算停止空转时间（以分钟为单位）
        //long stopIdleDurationMinutes = Duration.between(lineEfficiencyHour.getStartEmptyTime(), lineEfficiencyHour.getEndEmptyTime()).toMinutes();
        // 将 long 类型转换为 BigDecimal 类型
        //BigDecimal stopIdleDuration = BigDecimal.valueOf(Duration.between(lineEfficiencyHour.getStartEmptyTime(), lineEfficiencyHour.getEndEmptyTime()).toMinutes());
         // 设置停止空转时间
        //lineEfficiencyHour.setStopIdleDuration(BigDecimal.valueOf(Duration.between(lineEfficiencyHour.getStartEmptyTime(), lineEfficiencyHour.getEndEmptyTime()).toMinutes()));
        //合格线
        BeltDayTargetHis beltDayTargetHis = beltDayTargetHisService.selectLatest();
        lineEfficiencyHour.setQualifiedLine(beltDayTargetHis.getWorkEfficiency());

        //List<AverageMotorOperatingEfficiencyStats> statsList = beltPerformanceMinuteMapper.queryRecentEfficiencyStats(routeId);
        //List<BeltPerformanceMinuteRespVO> statsList = beltPerformanceMinuteMapper.queryRecentEfficiencyStats(routeId);
        // 查询最近一小时的数据
        List<BeltPerformanceMinuteRespVO> statsList = beltPerformanceMinuteMapper.queryRecentEfficiencyStats(routeId);
        //进行非空判断
        if (statsList == null || statsList.isEmpty()) {
            return null;
        }
        // 统计每种操作效率的状态数量
        Map<String, Long> classifiedEfficiencyCountMap = statsList.stream()
                .map(BeltPerformanceMinuteRespVO::getOperationEfficiency) // 直接调用实例方法
                .map(this::classifyEfficiency)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        // 计算总数量
        long totalCount = statsList.size();

        // 封装结果
        List<AverageMotorOperatingEfficiencyStats> result = new ArrayList<>();
        for (Map.Entry<String, Long> entry : classifiedEfficiencyCountMap.entrySet()) {
            String type = entry.getKey();
            long count = entry.getValue();
            BigDecimal percentage = BigDecimal.valueOf(count).divide(BigDecimal.valueOf(totalCount), 4, BigDecimal.ROUND_HALF_UP);

            AverageMotorOperatingEfficiencyStats stats = new AverageMotorOperatingEfficiencyStats();
            stats.setOperationEfficiency(new BigDecimal(type)); // 假设类型存储为BigDecimal
            stats.setCount(count);
            stats.setPercentage(percentage.multiply(BigDecimal.valueOf(100)));

            result.add(stats);
        }
        lineEfficiencyHour.setAverageMotorOperatingEfficiencyStats(result);

        //上一小时的开始
        //DateTime startTime = DateUtil.beginOfHour(DateUtil.offsetHour( new Date(), -1));
        //上一小时的结束
        //DateTime endTime = DateUtil.endOfHour(DateUtil.offsetHour(new Date(), -1));

        DateTime startTime = DateUtil.beginOfDay(new Date());
        DateTime endTime = DateUtil.endOfDay(new Date());

        // 负载率,空负载率,作业效率
        List<BeltRoutePerformanceHourRespVO> hour = baseMapper.getLineEfficiencyHourS(routeId, startTime, endTime);

        List<LoadRateAndWorkingEfficiency> loadRateAndWorkingEfficiencies = hour.stream().map(h -> {
            LoadRateAndWorkingEfficiency loadRateAndWorkingEfficiency = new LoadRateAndWorkingEfficiency();
            loadRateAndWorkingEfficiency.setWorkEfficiency(h.getWorkEfficiency());
            loadRateAndWorkingEfficiency.setAvgNoLoadRate(h.getAvgNoLoadRate());
            loadRateAndWorkingEfficiency.setAvgLoadRate(h.getAvgLoadRate());
            loadRateAndWorkingEfficiency.setBelongDate(h.getBelongDate());
            return loadRateAndWorkingEfficiency;
        }).collect(Collectors.toList());
        lineEfficiencyHour.setLoadRateAndWorkingEfficiencyList(loadRateAndWorkingEfficiencies);

        return lineEfficiencyHour;
    }
    private String classifyEfficiency(BigDecimal efficiency) {
        // 根据操作效率分类
        if (efficiency.compareTo(new BigDecimal("0.9")) >= 0) {
            return "0";
        } else if (efficiency.compareTo(new BigDecimal("0.7")) >= 0) {
            return "1";}
        else if (efficiency.compareTo(new BigDecimal("0.6")) >= 0) {
            return "2";}
        else if (efficiency.compareTo(new BigDecimal("0.5")) >= 0) {
            return "3";
        } else {
            return "4";
        }
    }


    @Autowired
    private BasicDeviceMapper basicDeviceMapper;
    @Autowired
    private FlowBasicMapper flowBasicMapper;

    @Autowired
    private BeltPerformanceHourMapper beltPerformanceHourMapper;
    @Autowired
    private BeltRoutePerformanceHourMapper beltRouteMapper;
    //远程调用接口
    @Autowired
    private FlowBasicFeign flowBasicFeign;
    @Override
    public List<Map<String, Object>> getBeltInfoById(Long id) {
        // 根据 ID 查询 flow_basic 表
        //FlowBasic flowBasic = flowBasicMapper.selectById(id);
//        flowBasicFeign.all()
        FlowBasicRespVO flowBasic = flowBasicMapper.searchById(id);
        if (flowBasic == null) {
            return null;
        }

        // 将 flow_name 按下划线 _ 分割
        String flowName = flowBasic.getFlowName();
        List<String> beltNames = Arrays.asList(flowName.split("-"));

        // 根据 beltName 查询 basic_device 表
        List<BasicDevice> devices = basicDeviceMapper.selectByDeviceNames(beltNames);
        if (devices == null) {
            return null;
        }
        // 获取所有皮带的 ID
        List<Integer> beltIds = devices.stream()
                .map(BasicDevice::getId)
                .collect(Collectors.toList());

        // 统计所有皮带的总长度
        BigDecimal totalBeltLength = flowBasic.getFlowDistance();
        /*double totalBeltLength = devices.stream()
                .filter(device -> device != null && device.getDeviceLength() != null)
                .mapToDouble(device -> device.getDeviceLength().doubleValue())
                .sum();*/

        // 根据 beltId 查询 belt_performance_hour 表
        List<BeltPerformanceHourRespVO> performances = beltPerformanceHourMapper.selectByBeltIds(beltIds);//上一小时数据
        if (performances == null) {
            return null;
        }
        // 计算每条皮带的运输效率和运输能耗
        Map<Integer, BasicDevice> deviceMap = devices.stream()
                .collect(Collectors.toMap(BasicDevice::getId, device -> device));

        List<Map<String, Object>> result = performances.stream().map(performance -> {
            BasicDevice device = deviceMap.get(performance.getBeltId().intValue());
            if (device == null) {
                // 返回一个空的 Map 或者跳过当前项
                return new HashMap<String, Object>(); // 返回一个空的 Map
            }
            BigDecimal totalTransport = performance.getTotalTransport() == null ? BigDecimal.ZERO : performance.getTotalTransport();
            BigDecimal allRuntime = performance.getLoadRuntime() == null ? BigDecimal.ZERO : performance.getLoadRuntime();
            BigDecimal totalPowerConsumption = performance.getTotalPowerConsumption() == null ? BigDecimal.ZERO : performance.getTotalPowerConsumption();

           /* BigDecimal transportEfficiency = allRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalTransport.divide(allRuntime, 4, BigDecimal.ROUND_HALF_UP);
            BigDecimal transportEnergyConsumption = totalTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalPowerConsumption.divide(totalTransport, 4, BigDecimal.ROUND_HALF_UP);*/
            // 检查 allRuntime 是否为 null 或者等于 0
            BigDecimal transportEfficiency = (allRuntime == null || allRuntime.compareTo(BigDecimal.ZERO) == 0)
                    ? BigDecimal.ZERO
                    : totalTransport.divide(allRuntime, 4, BigDecimal.ROUND_HALF_UP);

            // 检查 totalTransport 是否为 null 或者等于 0
            BigDecimal transportEnergyConsumption = (totalTransport == null || totalTransport.compareTo(BigDecimal.ZERO) == 0)
                    ? BigDecimal.ZERO
                    : totalPowerConsumption.divide(totalTransport, 4, BigDecimal.ROUND_HALF_UP);
            return new HashMap<String, Object>() {{
                put("beltName", device.getDeviceName());
                put("beltLength", device.getDeviceLength());
                put("transportEfficiency", transportEfficiency);
                put("transportEnergyConsumption", transportEnergyConsumption);
            }};
        }).collect(Collectors.toList());

        // 获取整条线路的性能记录
        //BeltRoutePerformanceHourRespVO respVO = beltRouteMapper.searchById(id);
        BeltRoutePerformanceHourRespVO respVO = beltRouteMapper.searchByRouteId(id);//最近一小时数据
        if (respVO == null) {
            return null;
        }
        //BeltRoutePerformanceHourRespVO respVO = BeltRoutePerformanceHourAssembler.entity2dto(routePerformance);

        // 计算整条线路的运输效率和运输能耗
        /*BigDecimal totalRouteTransport = routePerformance.getTotalTransport();
        BigDecimal totalRouteRuntime = routePerformance.getAllRuntime();
        BigDecimal totalRoutePowerConsumption = routePerformance.getTotalPowerConsumption();*/
        // respVO.setTotalTransport(BigDecimal.valueOf(10.0));
        BigDecimal totalRouteTransport = respVO.getTotalTransport();
        BigDecimal totalRouteRuntime = respVO.getAllRuntime();
        BigDecimal totalRoutePowerConsumption = respVO.getTotalPowerConsumption();
          // 检查 totalRouteTransport 和 totalRouteRuntime 是否为 null
        if (totalRouteTransport == null || totalRouteRuntime == null) {
            log.error("totalRouteTransport or totalRouteRuntime is null for id: {}", id);
            return null;
        }
        BigDecimal routeTransportEfficiency = totalRouteRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRouteTransport.divide(totalRouteRuntime, 4, BigDecimal.ROUND_HALF_UP);
        BigDecimal routeTransportEnergyConsumption = totalRouteTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRoutePowerConsumption.divide(totalRouteTransport, 4, BigDecimal.ROUND_HALF_UP);

        // 将总长度、整条线路的运输效率和运输能耗以及线路名称添加到结果中
        Map<String, Object> summary = new HashMap<>();
        summary.put("totalBeltLength", totalBeltLength);
        summary.put("routeTransportEfficiency", routeTransportEfficiency);
        summary.put("routeTransportEnergyConsumption", routeTransportEnergyConsumption);
        summary.put("flowName", flowName); // 添加整条线路的名称
        result.add(summary);

        return result;


    }


}
